#include <unordered_map>
#include <vector>
#include <iostream>
#include <string>
#include <unordered_set>
#include <cstring>
#include "ir.cpp"

using namespace std;

int op_table[256], id_table[256], num_table[256];

unordered_set<const string *> type_keys;
unordered_map<const string *, int> key_map;
unordered_map<const string *, int> ops_id_map;
unordered_set<const string *> binary_ops;
unordered_set<const string *> unary_ops;
unordered_set<string> *str_pool;
unordered_map<const string *, unordered_set<string>::iterator> *reverse_str_pool;

const string *NewOrFindString(const string &s)
{
    auto f = str_pool->find(s);
    if (f == str_pool->end())
    {
        auto g = str_pool->insert(s).first;
        auto v = &*g;
        reverse_str_pool->insert(make_pair(v, g));
        return v;
    }
    return &*f;
}

void Error(char *path, int line, int byte, const string &t)
{
    cout << path << " " << line << ':' << byte << " " << t << '\n';
}
void Error(const string &t)
{
    cout << t << '\n';
}

unordered_set<string> _multiop{
    "==", ">=", "<=", "!=", ">>", "<<",
    "&&", "||", "++", "--", "+=", "-=", "*=",
    "/=", "%=", ">>=", "<<=", "^=", "|=", "&=", "()"};

const char *invalid_number = "invalid number format", *err_operator_missing = "operator missing operand",
           *err_operand_missing = "operand missing operator", *err_unexpected_comma = "unexpected token ','",
           *err_unexpect_statement = "unexpected statement", *err_unexpect_token = "unexpected token",
           *invalid_stmt_begin = "invalid begin statement", *invalid_package_name = "invalid package name",
           *unexpect_end = "unexpected file end";

const string *key_if, *key_else, *key_fun, *key_then, *key_end, *key_while, *key_loop, *key_do, *key_until,
    *key_for, *key_struct, *key_new, *key_return, *key_let, *key_null, *key_elif, *key_break, *key_continue,
    *key_try, *key_catch, *key_final, *key_int, *key_char, *key_float, *key_string, *key_void, *str_break;

const string *ops_zxkh, *ops_yxkh, *ops_yzkh, *ops_ydkh, *ops_zzkh, *ops_zdkh,
    *ops_add, *ops_sub, *ops_mul, *ops_div, *ops_mod, *ops_lt, *ops_gt, *ops_eq, *ops_neq,
    *ops_gteq, *ops_lteq, *ops_not, *ops_ops, *ops_shr, *ops_shl, *ops_xor, *ops_or, *ops_and,
    *ops_bit_and, *ops_bit_or, *ops_add_assign, *ops_sub_assign, *ops_mul_assign,
    *ops_div_assign, *ops_mod_assign, *ops_bit_or_assign, *ops_bit_and_assign, *ops_xor_assign, *ops_shr_assign,
    *ops_shl_assign, *ops_comma, *ops_assign, *ops_point, *ops_at, *ops_mh, *ops_add_add, *ops_sub_sub, *ops_call;

unordered_map<const string *, unsigned int> priority;

enum keyword_t
{
    kw_id = 0,
    kw_if,
    kw_if_then,
    kw_elif,
    kw_elif_then,
    kw_else,
    kw_fun,
    kw_then,
    kw_end,
    kw_while,
    kw_while_then,
    kw_loop,
    kw_do,
    kw_until,
    kw_for,
    kw_struct,
    kw_new,
    kw_return,
    kw_map,
    kw_index,
    kw_list,
    kw_let,
    kw_call,
    kw_kh,
    kw_assign,
    kw_continue,
    kw_break,
    kw_try,
    kw_final,
    kw_catch,
    kw_int,
    kw_char,
    kw_float,
    kw_string,
    kw_void
};

enum ops_id
{
    ops_id_assign = 0,
    ops_id_add,
    ops_id_add_add
};

enum token_t
{
    tk_id = 0,
    tk_op,
    tk_num,
    tk_str,
    tk_eof,
    tk_break,
    tk_char
};

enum ast_t
{
    ast_node,
    ast_decl,
    ast_binary,
    ast_preUnary,
    ast_aftUnary,
    ast_call,
    ast_decl_var,
    ast_decl_function
};

void printDepth(int depth)
{
    while (depth--)
    {
        printf("  ");
    }
}

class Token
{
public:
    int line;
    int byte;
    const string *val;
    int type;
    Token(int t, int l, int b, const string &v)
    {
        line = l;
        byte = b;
        type = t;
        val = NewOrFindString(v);
    };
    void Print()
    {
        printf("[%d:%d %s]\n", line, byte, val->c_str());
    }
};

class ASTNode
{
public:
    Token *t;
    int node_t;

    ASTNode(Token *tk)
    {
        t = tk;
    }
    ASTNode(){};
    virtual ~ASTNode(){};
    virtual int type() { return ast_node; }
    virtual void print(int depth)
    {
        printDepth(depth);
        t->Print();
    }
};

class DeclareStmt : public ASTNode
{
    ASTNode *id;
    ASTNode *value;

public:
    int type() { return ast_decl; }
    DeclareStmt(Token *assign, ASTNode *left, ASTNode *right);
};

class IfStmt : public ASTNode
{
public:
    ASTNode *cond;
    ASTNode *body;
    IfStmt(Token *tk, ASTNode *s, ASTNode *b)
    {
        t = tk;
        cond = s;
        body = b;
    }

    void print(int depth)
    {
        printDepth(depth);
        printf("{if}\n");
        cond->print(depth + 1);
        body->print(depth + 1);
    }
};

class ForStmt : public ASTNode
{
public:
    ASTNode *init;
    ASTNode *cond;
    ASTNode *next;
    ASTNode *body;
    ForStmt(Token *tk, ASTNode *i, ASTNode *c, ASTNode *n, ASTNode *b)
    {
        t = tk;
        init = i;
        cond = c;
        next = n;
        body = b;
    }
    void print(int depth)
    {
        printDepth(depth);
        printf("{for}\n");
        if (init)
        {
            init->print(depth + 1);
        }
        if (cond)
        {
            cond->print(depth + 1);
        }
        if (next)
        {
            next->print(depth + 1);
        }
        body->print(depth + 1);
    }
};

class WhileStmt : public ASTNode
{
public:
    ASTNode *cond;
    ASTNode *body;
    WhileStmt(Token *tk, ASTNode *c, ASTNode *b)
    {
        t = tk;
        cond = c;
        body = b;
    }
    void print(int depth)
    {
        printDepth(depth);
        printf("{while}\n");
        cond->print(depth + 1);
        body->print(depth + 1);
    }
};

class ReturnStmt : public ASTNode
{
public:
    ASTNode *res;
    ReturnStmt(Token *op, ASTNode *n)
    {
        res = n;
        t = op;
    }
};

class DeclVarStmt : public ASTNode
{
public:
    Token *type_t;
    Token *left;
    ASTNode *right;

    DeclVarStmt(Token *tt, Token *l, ASTNode *r)
    {
        type_t = tt;
        left = l;
        right = r;
    }
    int type()
    {
        return ast_decl_var;
    }
    void print(int depth)
    {
        printDepth(depth);
        printf("{decl var}\n");
        printDepth(depth);
        printf("%s %s\n", type_t->val->c_str(), left->val->c_str());
        if (right)
        {
            right->print(depth + 1);
        }
    }
};

class DeclFuncStmt : public ASTNode
{
public:
    Token *type_t;
    Token *fun_name;
    vector<ASTNode *> *params;
    ASTNode *body;
    int type() { return ast_decl_function; }
    DeclFuncStmt(Token *tt, Token *fn, vector<ASTNode *> *ps, ASTNode *b)
    {
        type_t = tt;
        fun_name = fn;
        params = ps;
        body = b;
    }
    void print(int depth)
    {
        // printDepth(depth);
        // printf("{decl func}\n");

        // printDepth(depth);
        // body->print(depth + 1);

        printDepth(depth);
        printf("{func_def %s}\n", fun_name->val->c_str());
        printDepth(depth);
        printf("type:");
        type_t->Print();
        printDepth(depth);
        printf("args:");
        for (auto item = params->begin(), end = params->end(); item != end; item++)
        {
            (*item)->print(depth + 1);
        }
        printf("\n");
        if (body)
        {
            printDepth(depth);
            printf("body:");
            body->print(depth + 1);
        }
    }
};

class BinaryExpr : public ASTNode
{

public:
    ASTNode *left;
    ASTNode *right;
    int type() { return ast_binary; }
    BinaryExpr(Token *op, ASTNode *p1, ASTNode *p2)
    {
        t = op;
        left = p1;
        right = p2;
    };
    void print(int depth)
    {
        printDepth(depth);
        printf("{binary %s}\n", t->val->c_str());
        printDepth(depth);
        printf("left:");
        left->print(depth + 1);
        printDepth(depth);
        printf("right:");
        right->print(depth + 1);
    }
};

class PreUnaryExpr : public ASTNode
{
    ASTNode *value;

public:
    int type() { return ast_preUnary; }
    PreUnaryExpr(ASTNode *p, Token *op)
    {
        t = op;
        value = p;
    };
    void print(int depth)
    {
        printDepth(depth);
        printf("{pre unary %s}\n", t->val->c_str());
        printDepth(depth);
        printf("value:");
        value->print(depth + 1);
    }
};

class AftUnaryExpr : public ASTNode
{
    ASTNode *value;

public:
    AftUnaryExpr(ASTNode *p, Token *op)
    {
        t = op;
        value = p;
    };
    int type() { return ast_aftUnary; }
    void print(int depth)
    {
        printDepth(depth);
        printf("{aftUnary %s}\n", t->val->c_str());
        printDepth(depth);
        printf("value:");
        value->print(depth + 1);
    }
};

class CallExpr : public ASTNode
{
public:
    ASTNode *name;
    vector<ASTNode *> *params;
    int type() { return ast_call; }
    CallExpr(Token *tk, ASTNode *n, vector<ASTNode *> *p)
    {
        t = tk;
        name = n;
        params = p;
    }
    void print(int depth)
    {
        printDepth(depth);
        printf("{call }\n");
        printDepth(depth);
        printf("name: \n");
        printDepth(depth);
        name->print(depth + 1);
        printDepth(depth);
        printf("params: \n");
        for (auto f = params->begin(); f != params->end(); f++)
        {
            (*f)->print(depth + 1);
        }
    }
};

class Block : public ASTNode
{
public:
    vector<ASTNode *> *body;
    Block(Token *kh, vector<ASTNode *> *s)
    {
        t = kh;
        body = s;
    };
    void print(int depth)
    {
        printDepth(depth);
        printf("{block}\n");
        for (auto item = body->begin(), end = body->end(); item != end; item++)
        {
            (*item)->print(depth + 1);
        }
    }
};

class Lexer
{

public:
    char *path;
    FILE *fp;
    int line;
    int byte;

    Lexer(char *p, FILE *f);
    Token *getToken();
    void Error(char *p, int l, int b, const string &t);
};

class Parser
{
private:
    Lexer *lex;
    char *path;
    Token *on_tk;
    bool err;

public:
    Parser(char *path, FILE *fp);
    Token *getToken()
{
    // Token* t = lex->getToken();
    // cout << t->val->c_str() + '\n';
    // return t;
    return lex->getToken();
};
    vector<ASTNode *> *startCompile();
    vector<ASTNode *> *startParse(vector<ASTNode *> *temp);
    ASTNode *parseStatement();
    ASTNode *parseDefine(Token *t);
    ASTNode *parseDeclVar(Token *type, Token *left, Token *next);
    ASTNode *parseDeclFunction(Token *type, Token *left);
    ASTNode *parseExpr(Token *t, const string *end);
    ASTNode *parseCell(ASTNode *n, const string *end);
    ASTNode *parsePreUnaryExpr(ASTNode *right, Token *op);
    ASTNode *parseAftUnaryExpr(ASTNode *left, Token *op);
    ASTNode *parseCall(ASTNode *left, Token *kh);
    ASTNode *parseBlock(Token *t);

    void Error(const string &t)
    {
        printf("%s\n", t.c_str());
        err = true;
    }
    void Error(Token *tk, const string &t)
    {
        printf("%d %d %s\n", tk->line, tk->byte, t.c_str());
        err = true;
    };
};

DeclareStmt::DeclareStmt(Token *assign, ASTNode *left, ASTNode *right)
{
    id = left;
    value = right;
    t = assign;
}

Parser::Parser(char *p, FILE *file)
{
    // int init_line = 1;
    // int init_byte = 0;
    // line = &init_line;
    // byte = &init_byte;
    lex = new Lexer(p, file);
    err = false;
}

Lexer::Lexer(char *p, FILE *f)
{
    path = p;
    fp = f;
    line = 1;
    byte = 0;
}

void Lexer::Error(char *p, int l, int b, const string &t)
{
    cout << p << " " << l << ':' << b << " " << t << '\n';
}

Token *Lexer::getToken()
{
    char onget;
    for (;;)
    {
        onget = fgetc(fp);
        switch (onget)
        {
        case EOF:
        {
            return new Token(tk_eof, line, ++byte, "0");
        }
        case '\r':
            continue;
        case '\n':
            line++;
            byte = 0;
            continue;
        case '\t':
        case ' ':
            byte++;
            continue;
        case ';':
            return new Token(tk_break, line, ++byte, *str_break);
        default:
            break;
        }
        string onstr;
        if (onget == '\'')
        {
            onget = fgetc(fp);
            switch (onget)
            {
            case EOF:
            case '\n':
            case '\r':
            case '\'':
                Error(path, line, byte, "char literal can not be empty");
                return NULL;
            }
            bool escape = false;
            if (onget == '\\')
            {
                onget = fgetc(fp);
                switch (onget)
                {
                case '\\':
                    onstr += '\\';
                    break;
                case 'n':
                    onstr += '\n';
                    break;
                case 't':
                    onstr += '\t';
                    break;
                case 'r':
                    onstr += '\r';
                    break;
                case '\'':
                    onstr += '\'';
                    break;
                default:
                    Error(path, line, byte, "invalid escape symbol");
                    return NULL;
                }
            }
            else
            {
                onstr += onget;
            }
            onget = fgetc(fp);
            if (onget != '\'')
            {
                Error(path, line, byte, "char literal must have single byte");
                return NULL;
            }
            return new Token(tk_char, line, byte, onstr);
        }
        if (onget == '"')
        {
            for (;;)
            {
                onget = fgetc(fp);
                (byte)++;
                if (onget == '"')
                {
                    return new Token(tk_str, line, byte, onstr);
                }
                switch (onget)
                {
                case EOF:
                    Error(path, line, byte, "string literal missing end symbol");
                    return NULL;
                case '\\':
                    onget = fgetc(fp);
                    (byte)++;
                    switch (onget)
                    {
                    case '\\':
                        onstr += '\\';
                        continue;
                    case 'n':
                        onstr += '\n';
                        continue;
                    case 't':
                        onstr += '\t';
                        continue;
                    case 'r':
                        onstr += '\r';
                        continue;
                    case '"':
                        onstr += '"';
                        continue;
                    default:
                        Error(path, line, byte, "invalid escape symbol");
                        return NULL;
                    }
                default:
                    onstr += onget;
                }
            }
        }

        onstr += onget;
        if (op_table[onget])
        {
            onget = fgetc(fp);
            if (onget != EOF)
            {
                if (op_table[onget])
                {
                    string str(onstr + onget);
                    if (_multiop.find(str) == _multiop.end())
                    {
                        fseek(fp, -1, SEEK_CUR);
                        return new Token(tk_op, line, byte, onstr);
                    }
                    return new Token(tk_op, line, byte, str);
                }
                fseek(fp, -1, SEEK_CUR);
            }
            return new Token(tk_op, line, byte, onstr);
        }
        if (num_table[onget])
        {
            bool is_point = false;
            if (onget == '0')
            {
            }
            for (;;)
            {
                onget = fgetc(fp);
                if (num_table[onget])
                {
                    onstr += onget;
                }
                else if (onget == '.')
                {
                    if (is_point)
                    {
                        Error(path, line, byte, "error .");
                        return NULL;
                    }
                    is_point = true;
                    onstr += onget;
                }
                else
                {
                    fseek(fp, -1, SEEK_CUR);
                    return new Token(tk_num, line, byte, onstr);
                }
            }
        }

        for (;;)
        {

            onget = fgetc(fp);
            if (onget == EOF)
            {
                return new Token(tk_id, line, byte, onstr);
            }
            // cout << id_table[onget];
            if (id_table[onget])
            {
                fseek(fp, -1, SEEK_CUR);
                return new Token(tk_id, line, byte, onstr);
            }
            onstr += onget;
            // cout << onstr + '\n';
            byte++;
        }
    }
}


vector<ASTNode *> *Parser::startParse(vector<ASTNode *> *temp)
{
    Token *on_tk;
    bool flag = true;
    //只解析双目表达式
    ASTNode *expr;
    for(;;) {
        Token* t = getToken();
        if(t->type == tk_eof) {
            break;
        }
        expr = parseDefine(t);
        if(!expr) {
            break;
        }
        temp->push_back(expr);
    }

    auto f = temp->begin();
    while (f != temp->end())
    {
        (*f)->print(0);
        f++;
    }

    return temp;
}

ASTNode *Parser::parseBlock(Token *zdkh)
{
    vector<ASTNode *> *stmts = new vector<ASTNode *>();
    //todo
    for (;;)
    {
        Token *t = getToken();
        auto v = t->val;

        if (v == ops_ydkh)
        {
            break;
        }

        switch (t->type)
        {
        case tk_eof:
        {
            Error(unexpect_end);
            delete t;
            delete stmts;
            return NULL;
        }
        case tk_break:
        {
            delete t;
            continue;
        }
        case tk_id:
        {
            //todo 定义，声明语句
            if (type_keys.find(v) != type_keys.end())
            {
                auto f = parseDefine(t);
                if (!f || f->type() != ast_decl_var)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                stmts->push_back(f);
                continue;
            }
            if (v == key_if)
            {
                Token *next = getToken();
                if (next->val != ops_zxkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                auto satisfy = parseExpr(getToken(), ops_yxkh);
                if (satisfy == NULL)
                {
                    Error(err_unexpect_statement);
                    delete stmts;
                    delete satisfy;
                    return NULL;
                }

                next = getToken();

                //if 必须接块 {}
                if (next->val != ops_zdkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                auto body = parseBlock(next);
                if (next->val != ops_zdkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                stmts->push_back(new IfStmt(t, satisfy, body));
                continue;
            }
            if (v == key_for)
            {
                Token *nt = getToken();
                ASTNode *init, *cond, *next, *body;
                if (nt->val != ops_zxkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                nt = getToken();
                if (nt->val != str_break)
                {
                    init = parseExpr(nt, NULL);
                }
                nt = getToken();
                if (nt->val != str_break)
                {
                    cond = parseExpr(nt, NULL);
                }
                next = parseExpr(getToken(), ops_yxkh);

                nt = getToken();
                if (nt->val != ops_zdkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                body = parseBlock(nt);
                //判断back

                stmts->push_back(new ForStmt(t, init, cond, next, body));
                continue;
            }
            if (v == key_while)
            {
                Token *nt = getToken();
                ASTNode *cond, *body;
                if (nt->val != ops_zxkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                cond = parseExpr(getToken(), ops_yxkh);
                if (!cond)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                nt = getToken();
                if (nt->val != ops_zdkh)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                body = parseBlock(nt);
                if (!body)
                {
                    Error(err_unexpect_token);
                    delete stmts;
                    return NULL;
                }
                stmts->push_back(new WhileStmt(t, cond, body));
                continue;
            }

            if (v == key_return)
            {
                auto f = parseExpr(getToken(), NULL);
                if (!f)
                {
                    Error(err_unexpect_token);
                    return NULL;
                }
                return new ReturnStmt(t, f);
            }
        }
        case tk_num:
        case tk_str:
        {

            auto back = parseExpr(t, NULL);
            if (back == NULL)
            {
                Error(err_unexpect_statement);
                delete stmts;
                delete t;
                return NULL;
            }
            stmts->push_back(back);
            continue;
        }
        }
    }

    return new Block(zdkh, stmts);
}

void compileInit();

ASTNode *Parser::parseDefine(Token *type)
{
    //声明类型
    if (key_map.find(type->val) == key_map.end())
    {
        Error(err_unexpect_token);
        return NULL;
    }

    //变量名，函数名
    Token *next = getToken();
    switch (next->type)
    {
    case tk_id:
    {
        if (key_map.find(next->val) != key_map.end())
        {
            Error(err_unexpect_token);
            return NULL;
        }
        Token *nnext = getToken();
        switch (nnext->type)
        {
        //int x;
        case tk_break:
        {
            return new DeclVarStmt(type, next, NULL);
        }
        //int fun
        case tk_op:
        {
            //int x, y;
            if (nnext->val == ops_comma)
            {
            }
            if (nnext->val == ops_assign)
            {
                auto back = parseExpr(getToken(), NULL);
                if (!back)
                {
                    Error(err_unexpect_token);
                    return NULL;
                }
                return new DeclVarStmt(type, next, back);
            }
            if (nnext->val == ops_call)
            {
                Token *zdkh = getToken();
                if (zdkh->val != ops_zdkh)
                {
                    Error(err_unexpect_token);
                    return NULL;
                }
                auto body = parseBlock(zdkh);
                return new DeclFuncStmt(type, next, new vector<ASTNode *>(), body);
            }
            if (nnext->val == ops_zxkh)
            {
                auto back = parseDeclFunction(type, next);
                if (!back)
                {
                    return NULL;
                }
                return back;
            }
        }
        }
    }
    }

    return NULL;
}

ASTNode *Parser::parseDeclFunction(Token *type, Token *name)
{
    auto l = new vector<ASTNode *>();
    for (;;)
    {
        auto n = getToken();
        if (!n)
        {
            Error(unexpect_end);
            for (auto item = l->begin(), end = l->end(); item != end; item++)
            {
                delete *item;
            }
            delete l;
            delete type;
            delete name;
            return NULL;
        }
        //(int x, y)
        if (type_keys.find(n->val) != type_keys.end())
        {
            auto t = getToken();
            if (t->type == tk_id)
            {
                l->push_back(new PreUnaryExpr(new ASTNode(t), n));
                Token *end = getToken();
                if (end->val == ops_comma)
                {
                    continue;
                }
                else if (end->val == ops_yxkh)
                {
                    break;
                }
                delete l;
                Error(err_unexpect_token);
                return NULL;
            }
        }
    }
    //判断l?

    Token *next = getToken();
    if (next->val == ops_zdkh)
    {
        auto body = parseBlock(next);
        if (!body)
        {
            delete l;
            Error(err_unexpect_token);
            return NULL;
        }

        return new DeclFuncStmt(type, name, l, body);
    }
    else if (next->val == str_break)
    {
        return new DeclFuncStmt(type, name, l, NULL);
    }

    delete l;
    Error(err_unexpect_token);
    return NULL;
}

ASTNode *Parser::parseDeclVar(Token *type, Token *left, Token *next)
{
    auto back = parseExpr(getToken(), NULL);
    if (!back)
    {
        Error(err_unexpect_token);
        return NULL;
    }
    return new DeclVarStmt(type, left, back);
}

//用来指明最近解析的表达式是否为括号表达式
const string *last;

ASTNode *Parser::parseExpr(Token *t, const string *end)
{
    switch (t->type)
    {
    case tk_eof:
    {
        Error(t, unexpect_end);
        return NULL;
    }
    case tk_break:
    {
        if (end == NULL)
        {
            return new ASTNode(t);
        }
    }
    case tk_id:
    {
        auto f = key_map.find(t->val);
        if (f != key_map.end())
        {
            Error(t, err_unexpect_token);
            delete t;
            return NULL;
        }
    }
    case tk_num:
    case tk_str:
    case tk_char:
        return parseCell(new ASTNode(t), end);
    case tk_op:
    {
        if (binary_ops.find(t->val) != binary_ops.end())
        {
            Error(t, err_unexpect_token);
            delete t;
            return NULL;
        }
        //一元
        if (unary_ops.find(t->val) != unary_ops.end())
        {
            Token *next = getToken();
            if (next->type == tk_eof)
            {
                Error(next, unexpect_end);
                delete t;
                delete next;
                return NULL;
            }
            if (t->val == ops_add_add || t->val == ops_sub_sub)
            {
                switch (next->type)
                {
                case tk_id:
                {
                    if (key_map.find(next->val) != key_map.end())
                    {
                        Error(t, err_unexpect_token);
                        delete t;
                        delete next;
                        return NULL;
                    }
                }
                case tk_num:
                {
                    PreUnaryExpr *expr = new PreUnaryExpr(new ASTNode(next), t);
                    return parseCell(expr, NULL);
                }
                case tk_op:
                {
                    if (next->val == ops_zxkh)
                    {
                        auto back = parseExpr(getToken(), ops_yxkh);
                        if (!back)
                        {
                            delete next;
                            delete t;
                            return NULL;
                        }
                        return parseCell(new PreUnaryExpr(back, t), end);
                    }
                    Error(next, err_unexpect_token);
                    delete next;
                    delete t;
                    return NULL;
                }
                    Error(t, err_unexpect_token);
                    delete t;
                    delete next;
                    return NULL;
                }
            }
            Error(t, err_unexpect_token);
            delete t;
            delete next;
            return NULL;
        }
        if (t->val == ops_zxkh)
        {
            Token *next = getToken();
            if (next->type == tk_eof)
            {
                Error(next, unexpect_end);
                delete t;
                delete next;
                return NULL;
            }
            auto back = parseExpr(next, ops_yxkh);
            if (!back)
            {
                delete next;
                delete t;
                return NULL;
            }
            return parseCell(back, end);
        }
    }
    }
    Error(t, err_unexpect_token);
    delete t;
    return NULL;
}

ASTNode *Parser::parseCell(ASTNode *n, const string *end)
{
    Token *next = getToken();
    auto v = next->val;
    if (v == end || v == ops_comma)
    {
        if (v == ops_yxkh)
        {
            last = ops_yxkh;
        }
        return n;
    }
    switch (next->type)
    {
    case tk_break:
        return n;
    case tk_op:
    {
        if (binary_ops.find(v) != binary_ops.end())
        {
            auto t = getToken();
            // if(t->type == tk_eof) {
            //     Error(t, unexpect_end);
            //     delete n;
            //     delete t;
            //     return NULL;
            // }
            // if(t->val == ops_zxkh) {
            //     next = getToken();
            //     auto back = parseExpr(next, ops_yxkh);
            //     if(!back) {
            //         delete next;
            //         delete n;
            //         return NULL;
            //     }
            //     return new BinaryExpr(next, n, back);
            // }
            auto back = parseExpr(t, end);
            if (!back)
            {
                delete next;
                delete n;
                return NULL;
            }

            if (last == ops_yxkh)
            {
                return new BinaryExpr(next, n, back);
            }
            if (back->type() == ast_binary)
            {

                if (priority.find(back->t->val)->second >= priority.find(next->val)->second)
                {
                    ((BinaryExpr *)back)->left = new BinaryExpr(next, n, ((BinaryExpr *)back)->left);
                    return back;
                }
            }

            return new BinaryExpr(next, n, back);
        }
        if (unary_ops.find(v) != unary_ops.end())
        {
            if (v == ops_add_add || v == ops_sub_sub)
            {
                last = v;
                return parseCell(new AftUnaryExpr(n, next), end);
            }
            Error(next, err_unexpect_token);
            delete n;
            return NULL;
        }

        if (v == ops_zxkh)
        {
            //函数调用
            vector<ASTNode *> *l = new vector<ASTNode *>();
            for (;;)
            {
                auto back = parseExpr(getToken(), ops_yxkh);
                // back->print(0);
                l->push_back(back);
                if (last == ops_yxkh)
                {
                    break;
                }
            }

            return parseCell(new CallExpr(next, n, l), end);
        }

        if (v == ops_call)
        {
            return parseCell(new CallExpr(next, n, new vector<ASTNode *>()), end);
        }
    }
    }
    Error(next, err_unexpect_token);
    delete n;
    return NULL;
}

class VType
{
public:
    int size; //占用字节
    union
    {
        struct
        {
            char *name;
        } basic;
        struct
        {
            unordered_map<char *, VType *> *attrs;
        } stc;
    };
    virtual int type() { return 0; };
};

class BasicType : public VType
{
public:
    size_t index;       //基础变量类型的 类型int, char, str等
    const string *name; //变量类型的字面量 "int" "string" "char"
    BasicType(int i, const string *n)
    {
        index = i;
        name = n;
    }
    int type()
    {
        return index;
    }
};

enum basic_t
{
    basic_void = 0,
    basic_char,
    basic_short,
    basic_int,
    basic_long,
    basic_float,
    basic_double
};

static BasicType *type_void, *type_char, *type_int, *type_str;

const string *str_int, *str_char, *str_string;

class Value
{
public:
    VType *type; //返回值的类型
    Value(VType *t)
    {
        type = t;
    };
};

void IRInit()
{
    str_int = NewOrFindString("int");
    str_char = NewOrFindString("char");
    str_string = NewOrFindString("string");

    type_int = new BasicType(basic_int, str_int);
    type_char = new BasicType(basic_char, str_char);
};

Value *analyzeExpr(ASTNode *node)
{
    auto tk = node->t;
    auto v = tk->val;
    switch (node->type())
    {
    case ast_binary:
    {
        auto left = analyzeExpr(((BinaryExpr *)node)->left);
        if (!left)
        {
            return NULL;
        }
        auto right = analyzeExpr(((BinaryExpr *)node)->right);
        if (!right)
        {
            delete left;
            return NULL;
        }
        auto lt = left->type, rt = right->type;
        switch (lt->type())
        {
        case basic_int:
        {
            if (rt->type() == basic_int)
            {
                return new Value(type_int);
            }
            if (lt->type() == basic_char)
            {
                return new Value(type_char);
            }
            Error("invalid const operation");
            return NULL;
        }
        case basic_char:
        {
            if (rt->type() == basic_int)
            {
                return new Value(type_int);
            }
            if (lt->type() == basic_char)
            {
                return new Value(type_char);
            }
            Error("invalid const operation");
            return NULL;
        }
        }
    }
    case ast_node:
    {
        switch (tk->type)
        {
        case tk_num:
        {
            return new Value(type_int);
        }
        case tk_char:
            return new Value(type_char);
        default:
            return NULL;
        }
    }
    default:
    {
        break;
    }
    }
    return NULL;
}

void analyzeDefines(vector<ASTNode *>* node)
{
    for (auto item = node->begin(), end = node->end(); item != end; item++)
    {
        analyzeExpr(*item);
    }
}

int TEAMain(int argc, char *argv[])
{
    FILE *fp = fopen(argv[0], "rb");
    if (!fp)
    {
        cout << "Err:File " << argv[0] << " not exist\n";
        return -1;
    }

    compileInit();
    Parser parser = Parser(argv[0], fp);
    vector<ASTNode *> *temp = new vector<ASTNode *>();
    parser.startParse(temp);
    analyzeDefines(temp);

    return 0;
}

void compileInit()
{
    memset(id_table, 0, 256);
    memset(op_table, 0, 256);
    memset(num_table, 0, 256);
    str_pool = new unordered_set<string>();
    reverse_str_pool = new unordered_map<const string *, unordered_set<string>::iterator>();
    type_keys = unordered_set<const string *>();
    binary_ops = unordered_set<const string *>();
    unary_ops = unordered_set<const string *>();
    op_table['+'] = 1;
    op_table['-'] = 1;
    op_table['*'] = 1;
    op_table['/'] = 1;
    op_table['%'] = 1;
    op_table['>'] = 1;
    op_table['<'] = 1;
    op_table['='] = 1;
    op_table['!'] = 1;
    op_table['~'] = 1;
    op_table['^'] = 1;
    op_table['('] = 1;
    op_table[')'] = 1;
    op_table['['] = 1;
    op_table[']'] = 1;
    op_table['{'] = 1;
    op_table['}'] = 1;
    op_table['.'] = 1;
    op_table[','] = 1;
    op_table['|'] = 1;
    op_table['&'] = 1;
    op_table[':'] = 1;
    op_table['@'] = 1;
    num_table['0'] = 1;
    num_table['1'] = 1;
    num_table['2'] = 1;
    num_table['3'] = 1;
    num_table['4'] = 1;
    num_table['5'] = 1;
    num_table['6'] = 1;
    num_table['7'] = 1;
    num_table['8'] = 1;
    num_table['9'] = 1;
    id_table[0] = 1;
    id_table['@'] = 1;
    id_table['+'] = 1;
    id_table['-'] = 1;
    id_table['*'] = 1;
    id_table['/'] = 1;
    id_table['%'] = 1;
    id_table['>'] = 1;
    id_table['<'] = 1;
    id_table['='] = 1;
    id_table['!'] = 1;
    id_table['~'] = 1;
    id_table['"'] = 1;
    id_table['\''] = 1;
    id_table['\\'] = 1;
    id_table['^'] = 1;
    id_table['('] = 1;
    id_table[')'] = 1;
    id_table['['] = 1;
    id_table[']'] = 1;
    id_table['{'] = 1;
    id_table['}'] = 1;
    id_table['.'] = 1;
    id_table[','] = 1;
    id_table[' '] = 1;
    id_table['\n'] = 1;
    id_table['|'] = 1;
    id_table['&'] = 1;
    id_table['\r'] = 1;
    id_table[';'] = 1;
    id_table[':'] = 1;
    str_break = NewOrFindString(";");
    key_int = NewOrFindString("int");
    key_char = NewOrFindString("char");
    key_float = NewOrFindString("float");
    key_catch = NewOrFindString("catch");
    key_final = NewOrFindString("final");
    key_string = NewOrFindString("final");
    key_elif = NewOrFindString("elif");
    key_let = NewOrFindString("let");
    key_new = NewOrFindString("new");
    key_do = NewOrFindString("do");
    key_if = NewOrFindString("if");
    key_elif = NewOrFindString("elif");
    key_else = NewOrFindString("else");
    key_for = NewOrFindString("for");
    key_while = NewOrFindString("while");
    key_struct = NewOrFindString("struct");
    key_return = NewOrFindString("return");
    key_break = NewOrFindString("break");
    key_continue = NewOrFindString("continue");

    ops_mh = NewOrFindString(":");
    ops_at = NewOrFindString("@");
    ops_point = NewOrFindString(".");
    ops_assign = NewOrFindString("=");
    ops_comma = NewOrFindString(",");
    ops_zxkh = NewOrFindString("(");
    ops_zzkh = NewOrFindString("[");
    ops_zdkh = NewOrFindString("{");
    ops_yxkh = NewOrFindString(")");
    ops_yzkh = NewOrFindString("]");
    ops_ydkh = NewOrFindString("}");
    ops_add = NewOrFindString("+");
    ops_sub = NewOrFindString("-");
    ops_mul = NewOrFindString("*");
    ops_div = NewOrFindString("/");
    ops_mod = NewOrFindString("%");
    ops_lt = NewOrFindString("<");
    ops_gt = NewOrFindString(">");
    ops_eq = NewOrFindString("==");
    ops_neq = NewOrFindString("!=");
    ops_gteq = NewOrFindString(">=");
    ops_lteq = NewOrFindString("<=");
    ops_not = NewOrFindString("!");
    ops_ops = NewOrFindString("~");
    ops_shr = NewOrFindString(">>");
    ops_shl = NewOrFindString("<<");
    ops_xor = NewOrFindString("^");
    ops_or = NewOrFindString("||");
    ops_and = NewOrFindString("&&");
    ops_bit_and = NewOrFindString("&");
    ops_bit_or = NewOrFindString("|");
    ops_assign = NewOrFindString("=");
    ops_add_add = NewOrFindString("++");
    ops_sub_sub = NewOrFindString("--");
    key_try = NewOrFindString("try");
    ops_add_assign = NewOrFindString("+=");
    ops_sub_assign = NewOrFindString("-=");
    ops_mul_assign = NewOrFindString("*=");
    ops_div_assign = NewOrFindString("/=");
    ops_mod_assign = NewOrFindString("%=");
    ops_bit_or_assign = NewOrFindString("|=");
    ops_bit_and_assign = NewOrFindString("&=");
    ops_xor_assign = NewOrFindString("^=");
    ops_shr_assign = NewOrFindString(">>=");
    ops_shl_assign = NewOrFindString("<<=");
    ops_call = NewOrFindString("()");
    type_keys.insert(key_int);
    type_keys.insert(key_char);
    type_keys.insert(key_float);
    key_map.insert(make_pair(key_int, kw_int));
    key_map.insert(make_pair(key_float, kw_float));
    key_map.insert(make_pair(key_string, kw_string));

    ops_id_map.insert(make_pair(ops_assign, ops_id_assign));
    ops_id_map.insert(make_pair(ops_add, ops_id_add));
    ops_id_map.insert(make_pair(ops_add_add, ops_id_add_add));

    binary_ops.insert(ops_add);
    binary_ops.insert(ops_sub);
    binary_ops.insert(ops_mul);
    binary_ops.insert(ops_div);

    unary_ops.insert(ops_add_add);

    priority.insert(make_pair(ops_not, 3));
    priority.insert(make_pair(ops_ops, 3));
    priority.insert(make_pair(ops_mul, 5));
    priority.insert(make_pair(ops_div, 5));
    priority.insert(make_pair(ops_mod, 5));
    priority.insert(make_pair(ops_add, 6));
    priority.insert(make_pair(ops_sub, 6));
    priority.insert(make_pair(ops_shr, 7));
    priority.insert(make_pair(ops_shl, 7));
    priority.insert(make_pair(ops_lt, 8));
    priority.insert(make_pair(ops_lteq, 8));
    priority.insert(make_pair(ops_gt, 8));
    priority.insert(make_pair(ops_gteq, 8));
    priority.insert(make_pair(ops_eq, 9));
    priority.insert(make_pair(ops_neq, 9));
    priority.insert(make_pair(ops_bit_and, 10));
    priority.insert(make_pair(ops_xor, 11));
    priority.insert(make_pair(ops_bit_or, 12));
    priority.insert(make_pair(ops_and, 13));
    priority.insert(make_pair(ops_or, 14));
    priority.insert(make_pair(ops_add_assign, 16));
    priority.insert(make_pair(ops_sub_assign, 16));
    priority.insert(make_pair(ops_mul_assign, 16));
    priority.insert(make_pair(ops_div_assign, 16));
    priority.insert(make_pair(ops_mod_assign, 16));
    priority.insert(make_pair(ops_shr_assign, 16));
    priority.insert(make_pair(ops_shl_assign, 16));
    priority.insert(make_pair(ops_xor_assign, 16));
    priority.insert(make_pair(ops_bit_and_assign, 16));
    priority.insert(make_pair(ops_bit_or_assign, 16));
}

int main(int argc, char *argv[])
{

    cout.unsetf(ios::showpoint);
    if (argc < 2)
    {
        cout << "Err:No file input\n";
        return -1;
    }

    return TEAMain(argc - 1, argv + 1);
}
